import VectorLineElement from '@/paint/elements/VectorLineElement';
import Paint from '@/paint/Paint';
import IsPC from '@/methods/IsPc';
import RemoveSaveList from '@/utils/RemoveSaveList';
import { GameLevel, LevelMessage } from '../Setting';
import BaseView from './BaseView';
import Angle from '@/paint/utils/Angle';
import Point from '@/paint/utils/Point';
import Vector from '@/paint/utils/Vector';
import { SpotI } from '@/utils/CanvasUtils/CanvasType';

export default class GameView extends BaseView {

	/** 关卡数 */
	private levelIndex!: number;

	/** 地图信息 */
	private levelMessage!: LevelMessage;

	/** 地图 */
	private map: number[] = [];

	/** 鼠标悬停的线条 */
	private MouseHoverLine?: VectorLineElement;

	/** 移动事件列表 */
	private overEventList: RemoveSaveList<() => void> = new RemoveSaveList<() => void>();

	/** 为PC端 */
	private IsPc: boolean = IsPC();

	/** 结束事件列表 */
	public get OverEventList(): RemoveSaveList<() => void> {
		return this.overEventList;
	}

	/** 游戏是否结束 */
	public get IsGameOver(): Boolean {
		const map = this.map;
		const { order, map: Map, viewMap } = this.levelMessage;
		let endMap = order ? Map : viewMap;
		return map.length === endMap.length && map.every((v, i) => v === endMap[i]);
	}

	/** 鼠标样式 */
	public get MousePointer(): boolean {
		return this.Paint.Canvas.Cursor === "pointer";
	}

	public set MousePointer(isPointer: boolean) {
		this.Paint.Canvas.Cursor = isPointer ? "pointer" : "default";
	}

	/** 关卡序号 */
	public get LevelIndex(): number {
		return this.levelIndex;
	}

	public set LevelIndex(val: number) {
		this.levelIndex = val;
		this.GetMapData();
	}

	/**
	 * 构造函数
	 * @param el 画板元素
	 * @param levelIndex 关卡ID
	 */
	public constructor(el: HTMLCanvasElement, levelIndex: number) {
		super(el);
		this.LevelIndex = levelIndex;
	}

	/** 获取地图数据 */
	private GetMapData(): void {
		const { dimensional: val, order } = this.levelMessage = GameLevel[this.levelIndex];
		const viewMap = new Array((2 * val * val + 2 * val) * 3).fill(0);
		const Map = new Array((3 * val * val + val) * 3).fill(0);
		this.map = order ? Map : viewMap;
		this.MakeUI();
	}

	/** 重新计算界面 */
	private MakeUI(): void {
		const canvas = this.Paint.Canvas.Element;
		const { padding, dimensional } = this.levelMessage;
		const X = padding;
		const Y = padding;
		const Width = canvas.width - padding * 2;
		const Height = canvas.height - padding * 2;
		const angleRatio = Math.cos(new Angle(30).Value);
		const Height2 = Width / angleRatio + Width / (dimensional * 3 + 2) * dimensional + 50;
		const minHeigt = Math.min(Height, Height2);
		const ViewLength = (minHeigt - 50) / ((dimensional * 3 + 2) / angleRatio + dimensional);
		const calcWidth = (Width - ViewLength * (dimensional * 3 + 2)) / 2;
		const length = ViewLength * (dimensional * 3 + 2) / angleRatio / (dimensional * 2);
		this.Paint.Clear();
		this.MakeView(ViewLength, { X: X + calcWidth, Y: Y + 24 });
		this.MakeBody(length, { X: X + calcWidth, Y: Y + ViewLength * dimensional + 50 });
		this.Paint.AddEvent(this, "resize", () => {
			this.MakeUI();
		});
	}

	/** 添加小地图元素 */
	private MakeView(length: number, spot: SpotI): void {
		const paint: Paint = this.Paint;
		const { dimensional } = this.levelMessage;
		const sideLength = length * dimensional;
		const Radius = sideLength / 20;
		const viewList: Vector[] = [];
		const leftTop = new Vector(new Point(spot.X, spot.Y), new Angle(90), length);
		const viewOrigin = leftTop.RotateAngle(-90);
		const round = viewOrigin.RotateAngle(90).ToLength(sideLength).RotateAngle(-90).ToLength(sideLength / 2).RotateAngle(90).ToLength(Radius * 2);
		paint.CreatElement("round", {
			Spot: round.Start,
			Radius,
			StartAngle: new Angle(0),
			EndAngle: new Angle(360),
			BorderColor: "#000",
			LineWidth: Radius / 3
		});
		const viewTypeList = ["正视图", "侧视图", "俯视图"];
		for (let i = 0; i < 3; i++) {
			const viewFirst = viewOrigin.SetLength(length * (dimensional + 1) * i).To().SetLength(length);
			const firstLine = viewFirst.RotateAngle(90);
			for (let m = 0; m < dimensional; m++) {
				const lineOrigin = firstLine.SetLength(length * m).To().SetLength(length)
				if (m === 0) {
					const font = lineOrigin.RotateAngle(-90).ToLength(sideLength / 2).RotateAngle(-90);
					const { X, Y } = font.Start;
					paint.CreatElement("text", {
						Spot: { X, Y: Y - 5 },
						Text: viewTypeList[i],
						Color: "#000",
						BaseLine: "bottom",
						Align: "center",
						FontSize: 18,
					});
				}
				viewList.push(lineOrigin);
			}
			for (let i = 0; i < dimensional; i++) {
				const colOrigin = viewFirst.SetLength(length * i).To().SetLength(length);
				viewList.push(colOrigin);
				const colFirst = colOrigin.To().RotateAngle(90);
				for (let j = 0; j < dimensional; j++) {
					const rowOrigin = colFirst.SetLength(length * j).To().SetLength(length);
					viewList.push(rowOrigin);
					viewList.push(rowOrigin.To().RotateAngle(90));
				}
			}
		}
		this.AddViewEvent(viewList);
	}

	/** 添加小地图事件 */
	private AddViewEvent(viewList: Vector[]): void {
		const map = this.map;
		const { order, viewMap, style } = this.levelMessage;
		const paint: Paint = this.Paint;
		const isEdit = !order;
		const Map = isEdit ? map : viewMap;
		viewList.forEach((view, i) => {
			const val = Map[i];
			const type = val === 2 ? "dotted" as const : val === 1 ? "active" as const : "none" as const;
			const vector = { type, Vector: view, style, Disabled: !isEdit, Range: 45 };
			const element = paint.CreatElement("vector", vector);
			if (isEdit) {
				element.AddEvent("hover", () => {
					this.VectorHover(element);
				});
				element.AddEvent("click", () => {
					this.VectorClick(element, i);
				});
			}
		});
	}

	/** 添加蜂巢元素 */
	private MakeBody(length: number, spot: SpotI): void {
		const paint: Paint = this.Paint;
		const { dimensional } = this.levelMessage;
		const sideLength = length * dimensional;
		const Radius = sideLength / 30;
		const half = length * (dimensional / 2);
		const vectorList: Vector[] = [];
		const leftTop = new Vector(new Point(spot.X, spot.Y), new Angle(90), length);
		const origin = leftTop.ToLength(half).RotateAngle(-60).ToLength(length * dimensional).RotateAngle(180);
		const round = origin.RotateAngle(-120).ToLength(half).RotateAngle(-60).ToLength(half).ToLength(Radius * 2);
		paint.CreatElement("round", {
			Spot: round.Start,
			Radius,
			StartAngle: new Angle(0),
			EndAngle: new Angle(360),
			BorderColor: "#000",
			LineWidth: Radius / 3
		});
		for (let i = 0; i < 3; i++) {
			const firstLine = origin.RotateAngle(i * 120);
			for (let m = 0; m < dimensional; m++) {
				vectorList.push(firstLine.SetLength(length * m).To().SetLength(length));
			}
			const groupOrigin = firstLine.SetLength(length * dimensional).To().SetLength(length).RotateAngle(120);
			for (let j = 1; j <= dimensional; j++) {
				const firstGroup = groupOrigin.SetLength(length * j).To().SetLength(length).RotateAngle(60);
				for (let k = 0; k < dimensional; k++) {
					const firstRow = firstGroup.SetLength(length * k).To().SetLength(length);
					vectorList.push(firstRow);
					vectorList.push(firstRow.RotateAngle(60));
					vectorList.push(firstRow.RotateAngle(120));
				}
			}
		}
		this.AddBodyEvent(vectorList);
	}

	/** 添加蜂巢事件 */
	private AddBodyEvent(vectorList: Vector[]): void {
		const paint: Paint = this.Paint;
		const map = this.map;
		const { order, map: mapSave, style } = this.levelMessage;
		const isEdit = order;
		const Map = isEdit ? map : mapSave;
		vectorList.forEach((vector, i) => {
			const type = Map[i] === 1 ? "active" as const : "none" as const;
			const vectorI = { type, Vector: vector, style, Disabled: !isEdit, Range: 30 };
			const element = paint.CreatElement("vector", vectorI);
			if (isEdit) {
				element.AddEvent("hover", () => {
					this.VectorHover(element);
				});
				element.AddEvent("click", () => {
					this.VectorClick(element, i);
				});
			}
		});
	}

	/** 悬停蜂巢线条 */
	private VectorHover(element: VectorLineElement): void {
		const type = element.Type;
		const isPc = this.IsPc;
		const onHover = element.OnHover;
		if (type !== "active" && type !== "dotted") {
			element.Type = isPc && onHover ? "hover" : "none";
		}
		if (this.IsPc) {
			this.VectorMouseCursor(element);
		}
	}

	/** 悬停蜂巢线条的鼠标样式 */
	private VectorMouseCursor(element: VectorLineElement): void {
		if (element.OnHover) {
			this.MousePointer = true;
			this.MouseHoverLine = element;
		} else if (this.MouseHoverLine === element) {
			this.MousePointer = false;
		}
	}

	/** 单击蜂巢线条 */
	private VectorClick(element: VectorLineElement, index: number): void {
		let type = element.Type;
		const onHover = element.OnHover;
		const isPc = this.IsPc;
		const order = this.levelMessage.order;
		if (type === "none" || type === "hover") {
			element.Type = "active";
		} else if (type === "active") {
			element.Type = !order ? "dotted" : isPc && onHover ? "hover" : "none";
		} else if (!order && type === "dotted") {
			element.Type = isPc && onHover ? "hover" : "none";
		}
		type = element.Type;
		this.map[index] = type === "active" ? 1 : !order && type === "dotted" ? 2 : 0;
		this.CheckGameOver();
	}

	/** 检查游戏是否结束 */
	private CheckGameOver() {
		if (this.IsGameOver) {
			const length = GameLevel.length - 1;
			if (this.levelIndex < length) {
				setTimeout(() => {
					alert("下一关");
					this.LevelIndex++;
				}, 100);
			} else {
				setTimeout(() => {
					alert("恭喜全部通关");
					this.overEventList.List.forEach(({ value: event }) => {
						event();
					});
				}, 100);
			}
		} else {
		}
	}

	/** 添加游戏结束事件 */
	public AddOverEvent(event: VoidFunction): VoidFunction {
		return this.overEventList.Add(event).remove;
	}
}
